package com.bourne.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.generator.config.IFileCreate;
import com.bourne.annotation.LambdaParam;
import com.bourne.model.BaseCoreDO;
import com.bourne.service.BaseCoreService;
import com.bourne.util.ClassUtil;
//import liquibase.pro.packaged.E;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program core-service
 * @description: 简单的条件查询分页你封装
 * @author: bourne
 * @create 2021-37-01 12:37:27
 **/
@Service
//@Primary
public class BaseCoreServiceImpl<M extends BaseMapper<T>, T extends BaseCoreDO>
        extends ServiceImpl<M, T> implements BaseCoreService<M, T> {

    @Autowired(required = false)
    protected M mapper;

    @Autowired
    private ClassUtil classUtil;

    @Override
    public QueryWrapper<T> getQueryWrapper(T bean, Class<T> classes, boolean superFields) {

        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        try {
            Field[] declaredFields = classes.getDeclaredFields();
            Map<Integer, String> ascSortMap = new HashMap<>();
            Map<Integer, String> desSortMap = new HashMap<>();
            ArrayList<Field> fieldArrayList = new ArrayList<>(Arrays.asList(declaredFields));
            if (superFields) {
                Field[] superDeclaredFields = classes.getSuperclass().getDeclaredFields();
                fieldArrayList.addAll(Arrays.asList(superDeclaredFields));
            }
            for (Field field : fieldArrayList) {
                Method method = bean.getClass().getMethod("get" + classUtil.uppercase(field.getName()));
                if (!field.isAnnotationPresent(LambdaParam.class)) {
                    continue;
                }
                String invoke = method.invoke(bean) + "";
                LambdaParam annotation = field.getAnnotation(LambdaParam.class);
                boolean orderByAsc = annotation.orderByAsc();
                boolean orderByDes = annotation.orderByDes();
                boolean dateLike = annotation.dataLike();
                boolean leftLike = annotation.leftLike();
                boolean rightLike = annotation.rightLike();
                String value = annotation.value();

                if (StringUtils.isNotBlank(invoke) && !StringUtils.equals("null", invoke)){
                    if (dateLike) {
                        queryWrapper.like(value, invoke);
                    } else if (leftLike) {
                        queryWrapper.likeLeft(value, invoke);
                    } else if (rightLike) {
                        queryWrapper.likeRight(value, invoke);
                    } else {
                        queryWrapper.eq(value, invoke);
                    }
                }

                int sortNum = annotation.sortNum();
                if (orderByAsc) {
                    ascSortMap.put(sortNum, value);
                }
                if (orderByDes) {
                    desSortMap.put(sortNum, value);
                }
            }

            if (!ascSortMap.isEmpty()) {
                LinkedHashMap<Integer, String> collect = ascSortMap.entrySet().stream().sorted(Map.Entry.comparingByKey())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
                for (Integer key : collect.keySet()) {
                    queryWrapper.orderByAsc(collect.get(key));
                }
            }

            if (!desSortMap.isEmpty()) {
                LinkedHashMap<Integer, String> collect = desSortMap.entrySet().stream().sorted(Map.Entry.comparingByKey())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
                for (Integer key : collect.keySet()) {
                    queryWrapper.orderByDesc(collect.get(key));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return queryWrapper;
    }

    /**
     * 1 - 2 集合的差集
     * @param firstArrayList
     * @param secondArrayList
     * @param fieldName
     * @return
     */
    @Override
    public List<T> diffList(List<T> firstArrayList, List<T> secondArrayList, String fieldName) {
        List<T> collect = new ArrayList<>();
        firstArrayList.forEach(item -> {
            List<String> list = secondArrayList.stream().map(t -> getMethod(t, fieldName)).collect(Collectors.toList());
            if (!list.contains(getMethod(item, fieldName))) {
                collect.add(item);
            }
        });
        return collect;
    }

    /**
     * 交集
     * @param firstArrayList
     * @param secondArrayList
     * @param fieldName
     * @return
     */
    @Override
    public List<T> intersection(List<T> firstArrayList, List<T> secondArrayList, String fieldName) {

        return firstArrayList.stream()
                .filter(item -> secondArrayList.stream().map(t -> getMethod(t, fieldName))
                        .collect(Collectors.toList()).contains(getMethod(item, fieldName)))
                .collect(Collectors.toList());
    }

    @SneakyThrows
    private String getMethod(T bean, String fieldName) {
        Method method = bean.getClass().getMethod("get" + classUtil.uppercase(fieldName));
        return method.invoke(bean) + "";
    }

    /**
     * 执行之前 登录用户信息添加
     * @param t
     * @return
     */
    @Override
    public Object preExecute(T t) {
//        LoginUser loginUser = AuthInterceptor.threadLocal.get();
//        if (loginUser != null) {
//            t.setCreateUser(loginUser.getId());
//            t.setUpdateUser(loginUser.getId());
//        }
        return t;
    }

    /**
     * 执行之后
     * @param t
     * @return
     */
    @Override
    public Object postExecute(T t) {
        return null;
    }

    /**
     * 数据insert操作
     * @param entity
     * @return
     */
    @Override
    public int insert(T entity) {
        entity = (T)preExecute(entity);
        return mapper.insert(entity);
    }
}
